package com.goktech.commons.utils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PropertyUtils {

	private final static Logger log = LoggerFactory.getLogger(PropertyUtils.class);
	
	private  Class<?> clazz;
	
	private Map<String,Method> cachemap;
	
	private PropertyDescriptor propertyDescriptor;
	
	public PropertyUtils(Class<?> clazz) {
		super();
		this.clazz = clazz;
		cachemap = new HashMap<String,Method>();
	}

	public static PropertyDescriptor getPropertyDescriptor(Class<?> cla,String propertyName){
		StringBuffer sb = new StringBuffer();//
		Method setMethod = null;
		Method getMethod = null;
		PropertyDescriptor pd = null;
		
		Field field = null;
		Field[] fields = cla.getDeclaredFields();
		
		while((fields != null && fields.length > 0) &&  field == null) {
			for(Field temp : fields) {
				if(temp.getName().equals(propertyName)) {
					field = temp;
					break;
				}
				log.info("name:{}",temp.getName());
			}
			break;
		}
		try{
			if(field == null)
			field = cla.getDeclaredField(propertyName);//根据字段名来获取字段
			if(field != null){
				//构建方法的后缀  
	            String methodEnd = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);  
	            sb.append("set" + methodEnd);//构建set方法  
	            setMethod = cla.getMethod(sb.toString(), new Class[]{ field.getType() }); 
	            sb.delete(0, sb.length());//清空整个可变字符串  
	            sb.append("get" + methodEnd);//构建get方法  
	            //构建get 方法  
	            System.out.println(sb.toString());
	            getMethod = cla.getMethod(sb.toString(), new Class[]{ });
	          //构建一个属性描述器 把对应属性 propertyName 的 get 和 set 方法保存到属性描述器中  
	          pd = new PropertyDescriptor(propertyName, getMethod, setMethod);
			}else {
				log.warn("{} 在 {}不存在",propertyName,cla.getName());
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
		return pd;
	}
	
	public static void setProperty(Object object,String propertyName,Object value){
		Class<?> clazz = object.getClass();
		PropertyDescriptor pd = getPropertyDescriptor(clazz, propertyName);
		Method setMethod = pd.getWriteMethod();//从属性描述其中获取set方法
		try{
			setMethod.invoke(object,new Object[]{value});//调用set方法讲舛讹如的value值保存属性中
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static Object getProperty(Object obj, String propertyName){
		Class<?> clazz = obj.getClass();//获取对象的类型  
	    PropertyDescriptor pd = getPropertyDescriptor(clazz,propertyName);//获取 clazz 类型中的 propertyName 的属性描述器  
	    Method getMethod = pd.getReadMethod();//从属性描述器中获取 get 方法  
	    Object value =null ;  
	    try {  
	        value = getMethod.invoke(obj, new Object[]{});//调用方法获取方法的返回值  
	    } catch (Exception e) {  
	        e.printStackTrace();  
	    }  
	    return value;//返回值  
	}
	
	public PropertyDescriptor getCachePropertyDescriptor(String propertyName){
		StringBuffer sb = new StringBuffer();//
		Method setMethod = null;
		Method getMethod = null;
		PropertyDescriptor pd = null;
		
		Field field = null;
		Field[] fields = this.clazz.getDeclaredFields();
		
		while((fields != null && fields.length > 0) &&  field == null) {
			for(Field temp : fields) {
				if(temp.getName().equals(propertyName)) {
					field = temp;
					break;
				}
				//log.debug("name:{}",temp.getName());
			}
			break;
		}
		try{
			if(field == null)
			field = clazz.getField(propertyName);//根据字段名来获取字段
			if(field != null){
				//构建方法的后缀  
	            String methodEnd = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);  
	            sb.append("set" + methodEnd);//构建set方法  
	            setMethod = clazz.getMethod(sb.toString(), new Class[]{ field.getType() }); 
	            sb.delete(0, sb.length());//清空整个可变字符串  
	            sb.append("get" + methodEnd);//构建get方法  
	            //构建get 方法  
	            getMethod = clazz.getMethod(sb.toString(), new Class[]{ });
	          //构建一个属性描述器 把对应属性 propertyName 的 get 和 set 方法保存到属性描述器中  
	          pd = new PropertyDescriptor(propertyName, getMethod, setMethod);
			}else {
				log.warn("{} 在 {}不存在",propertyName,clazz.getName());
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
		return pd;
	}
	
	public synchronized void setCacheProperty(Object object,String propertyName,Object value){
		Method setMethod;
		if(cachemap.get(propertyName) == null){
			try {
				initPropertyDescriptor(propertyName);//初始化set方法对象
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			} catch (SecurityException e) {

			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (IntrospectionException e) {
				e.printStackTrace();
			}			
			setMethod = propertyDescriptor.getWriteMethod();//从属性描述其中获取set方法
		}else{
			setMethod = cachemap.get(propertyName);
		}
		try{
			setMethod.invoke(object,new Object[]{value});//调用set方法将的value值保存属性中
		}catch (Exception e) {
			log.error("Object->Name : {},propertyName : {} ,value : {},paramsType:{} message:{}",object.getClass().getName(),propertyName,setMethod.getParameterTypes(),value,e.getMessage());
		}
	}
	
	public Object getCacheProperty(Object obj, String propertyName){
		Method getMethod;
		if(cachemap.get(propertyName) == null){
			try {
				initPropertyDescriptor(propertyName); //初始化set方法
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (IntrospectionException e) {
				e.printStackTrace();
			}
			getMethod = propertyDescriptor.getReadMethod();//从属性描述器中获取 get 方法
		}else{
			getMethod = cachemap.get(propertyName);
		}
		  
	    Object value =null ;  
	    try {  
	        value = getMethod.invoke(obj, new Object[]{});//调用方法获取方法的返回值  
	    } catch (Exception e) { 
	    	log.error("error:{}",e.getMessage());
	    	log.error("propertyName->{}",propertyName);
	        e.printStackTrace();  
	    }  
	    return value;//返回值  
	   }
	
	public void initPropertyDescriptor(String name) throws NoSuchFieldException, SecurityException, IntrospectionException, NoSuchMethodException{
		StringBuffer sb = new StringBuffer();//
		Method setMethod = null;
		Method getMethod = null;
		if(StringUtils.isEmpty(name)){
			throw new NullPointerException("name not null");
		}
		Field field = clazz.getDeclaredField(name);//根据字段名来获取字段
		//构建方法的后缀  
	    String methodEnd = name.substring(0, 1).toUpperCase() + name.substring(1);  
	    sb.append("set" + methodEnd);//构建set方法  
	    setMethod = clazz.getMethod(sb.toString(), new Class[]{ field.getType() }); 
	    sb.delete(0, sb.length());//清空整个可变字符串  
	    sb.append("get" + methodEnd);//构建get方法  
	    getMethod = clazz.getMethod(sb.toString(), new Class[]{ });
	    propertyDescriptor = new PropertyDescriptor(name, getMethod, setMethod);
	}
	
	public void LoadProperty(Object obj,Map<String,Object> params) {
		for(String key : params.keySet()) {
			setCacheProperty(obj,key,params.get(key));
		}
	}
	
}
